﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace Team6_Algorithms.Filters
{
    /// <summary>
    /// Made by Dylan snel && Pascal schotman
    /// </summary>
     public class Median
    {
         public static int[] RedHistogram;
         public static int[] GreenHistogram;
         public static int[] BlueHistogram;


         public static bool applyFilter(Bitmap B, int MASK_SIZE)
         {



             Bitmap bSrc = (Bitmap)B.Clone();

             BitmapData BmData = B.LockBits(new Rectangle(0, 0, B.Width, B.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
             BitmapData BmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

             int stride = BmData.Stride;

             System.IntPtr Scan0 = BmData.Scan0;
             System.IntPtr SrcScan0 = BmSrc.Scan0;

             unsafe
             {
                 byte* p = (byte*)(void*)Scan0;
                 byte* pSrc = (byte*)(void*)SrcScan0;

                 p += ((MASK_SIZE - 1) / 2) * stride;
                 p += ((MASK_SIZE - 1) / 2) * 3;
                 pSrc += ((MASK_SIZE - 1) / 2) * stride;
                 pSrc += ((MASK_SIZE - 1) / 2) * 3;

                 int nOffset = B.Width % 4;
                 int nWidth = B.Width - MASK_SIZE + 1;
                 int nHeight = B.Height - MASK_SIZE + 1;

                 for (int y = 0; y < nHeight; ++y)
                 {
                     for (int x = 0; x < nWidth; ++x)
                     {
                         fill_histogram(pSrc, MASK_SIZE, stride);
                         p[0] = (byte)find_median(BlueHistogram, MASK_SIZE);
                         p[1] = (byte)find_median(GreenHistogram, MASK_SIZE);
                         p[2] = (byte)find_median(RedHistogram, MASK_SIZE);
                         p += 3;
                         // add 3 pixels to the address? possibly
                         // at least, this is moving through the pic
                         // or maybe 3 bytes
                         pSrc += 3;
                     }
                     // but then here we add the padding... at the end of every row
                     p += nOffset;
                     pSrc += nOffset;
                 }
             }

             B.UnlockBits(BmData);
             bSrc.UnlockBits(BmSrc);

             return true;
         }

         private static unsafe void fill_histogram(byte* P, int MASK_SIZE, int STRIDE)
         {
             RedHistogram = new int[256];
             GreenHistogram = new int[256];
             BlueHistogram = new int[256];

             byte* FillPointer = P;
             int Boundary = (MASK_SIZE - 1) / 2;
             for (int y = -Boundary; y <= Boundary; ++y)
             {
                 for (int x = -Boundary; x <= Boundary; ++x)
                 {
                     RedHistogram[FillPointer[2 + (x * 3) + (y * STRIDE)]]++;
                     GreenHistogram[FillPointer[1 + (x * 3) + (y * STRIDE)]]++;
                     BlueHistogram[FillPointer[0 + (x*3) + (y*STRIDE) ]]++;

                 }
             }
                          
         }

         private static int find_median(int[] HISTO, int MASK_SIZE)
         {
             int Median = ((MASK_SIZE * MASK_SIZE) + 1) / 2;
             int Counter =0;
             for (int i = 0; i < 256; i++)
             {
                 Counter += HISTO[i];
                 if (Counter >= Median)
                 {
                     return i;
                 }
             }


             throw new Exception("SomethingWentWrongException has Occured");
         }

    }

    
}
